home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-10-11 | 31.8 KB | 1,240 lines | [TEXT/KAHL] |
- /*
- ** File: WebStat.cp
- **
- ** A transmission statistics summary program for MacHTTP log output
- **
- ** Author: Philip Harvey (phil@nsun.phy.queensu.ca)
- ** Physics Dept
- ** Queen's University
- **
- ** Revisions: 03/24/94 - V 1.0 - original
- ** 03/25/94 - V 1.1 - fixed array indexing problem
- ** 03/28/94 - V 1.2 - added anchors for lists; converted code to C++
- ** 03/29/94 - V 1.3 - added exclusion option and application icon
- ** - changed all byte counts from long to double
- ** 03/30/94 - V 1.4 - changed subdomain list to not reverse numerical entries
- ** - placed numerical entries at end of list
- ** 03/31/94 - V 1.5 - added config file and moved exclusions into config
- ** 04/04/94 - V 1.6 - added ADDRESSES Long/Short option
- ** - changed MESSAGES syntax from True/False to On/Off
- ** - added DOMAIN command to config file
- ** 04/08/94 - V 1.7 - added comprehensive list of Domain names to config file
- ** - changed spacing to accomodate longer domain names
- ** 04/11/94 - V 1.7.1 - delete trailing '/' if found in file names
- ** 04/14/94 - V 1.8 - ignored improperly formatted lines in log file
- ** 05/13/94 - V 1.9 - added SUMMARIZE options; changed to Symantec C++ 7.0
- ** - fixed quirk where days with no transfers were ignored
- ** 06/06/94 - V 2.0 - truncate filenames at '$' because of new cgi formatting
- ** - added check on time_t values passed to GetNumDays()
- ** - added format file (replaces SUMMARIZE option of V1.9)
- ** 08/11/94 - V 2.1 - removed limit on number of EXCLUDE and DOMAIN statements
- ** - sort numerical addresses properly
- ** 09/27/94 - V 2.2 - added DNSLOOKUP option
- ** 09/28/94 - V 2.3 - added progress indicator if MESSAGES Off
- ** - allows background processing if MESSAGES Off
- ** - fixed small bug in DNS lookups
- ** - Cmd-. aborts processing if MESSAGES Off
- ** - MESSAGES Off is now the default
- ** 09/28/94 - V 2.3.1 - fixed problem in event handling during DNS lookups
- ** - fixed problem with output going to system folder broken in 2.3
- ** 10/02/94 - V 2.3.2 - changed progress indicator; added stop button
- ** - re-fixed small bug in DNS lookups lost in 2.3.1
- ** 10/03/94 - V 2.3.3 - fixed problem which could cause crash if stop button pressed
- ** - message dialog box is now properly activated
- ** 10/11/94 - V 2.3.4 - progress bar now displays properly on B&W screens
- **
- ** Notes: For updates, the version number must be changed in the progress dialog title, in
- ** the program_name variable, and 3 times in the 'vers' resource.
- */
-
- #include <ctype.h>
- #include <string.h>
- #include <stdlib.h>
- #include "WebStat.h"
- #include "TCPLib.h"
-
- enum {
- kStopButtonItem = 1,
- kStaticTextItem,
- kProgressIndicatorItem
- };
-
- extern "C" void HandleEvents(void);
-
- /*
- ** static string definitions
- */
- static char * config_file = "WebStat.config";
- static char * def_log_file = "MACHTTP.LOG";
- static char * def_out_file = "WebStat.html";
- static char * def_fmt_file = "WebStat.format";
- static char * program_name = "WebStat 2.3.4";
-
- /*
- ** The following constants specify the number of array elements by which the
- ** statistics lists should grow each time more memory is required:
- **
- ** If the numbers are too small memory may become fragmented due to excess
- ** reallocations and the program will run more slowly, and if the numbers are
- ** too large more memory than necessary will be used.
- **
- ** If memory and/or speed are a concern, these numbers can be optimized for
- ** your individual needs.
- */
- const long kDateIncr = 1000; // for date list (this will do for 3 years)
- const long kHourIncr = 24; // for hour list (only 24 hours in a day)
- const long kWDayIncr = 7; // for weekday list (7 days in a week)
- const long kDomainIncr = 200; // for domain list (alot of countries)
- const long kSubDomainIncr = 5000; // for subdomain list (alot of computers)
- const long kFileIncr = 5000; // for archive file list (alot of files)
-
- const long kExcludeIncr = 100; // for list of exclusions (EXCLUDE statements)
- const long kCountryIncr = 500; // for country list (DOMAIN statements)
- const long kDNSListIncr = 500; // for DNS lookup list
-
- /*
- ** definitions of static member variables
- */
- unsigned long StatList::totalFiles = 0;
- double StatList::totalBytes = 0;
-
- /*-----------------------------------------------------------------------------------------
- ** Utility routines
- */
-
- /* strcmpi - compare two strings, ignoring case, and sorting special characters last */
- static int strcmpi(const char *str1, const char *str2)
- {
- char c1,c2;
-
- for (;; ++str1, ++str2) {
- c1 = toupper(*str1);
- c2 = toupper(*str2);
- if (c1==c2) {
- if (c1) continue;
- break;
- }
- if (c1 < c2) {
- if (!isupper(c1) && isupper(c2)) return(1);
- else return(-1);
- }
- if (c1 > c2) {
- if (isupper(c1) && !isupper(c2)) return(-1);
- else return(1);
- }
- }
- return(0);
- }
-
- /* strcmpiPart - compare two strings, ignoring case, and stopping at the end of str1 */
- static int strcmpiPart(const char *str1, const char *str2)
- {
- char c1,c2;
-
- for (;; ++str1, ++str2) {
- c1 = toupper(*str1);
- c2 = toupper(*str2);
- if (!c1) break;
- if (c1 < c2) return(-1);
- if (c1 > c2) return(1);
- }
- return(0);
- }
-
- /* strcmpiWild - compare two strings, ignoring case, allow wildcards */
- static int strcmpiWild(const char *str1, const char *str2)
- {
- char c1,c2;
-
- for (;;) {
- c1 = toupper(*str1);
- c2 = toupper(*str2);
- if (c1=='*' || c2=='*') return(0);
- if (c1 < c2) return(-1);
- if (c1 > c2) return(1);
- if (!c1) break;
- ++str1;
- ++str2;
- }
- return(0);
- }
-
- /* strtokQuote - strtok routine with quoted strings allowed */
- static char *strtokQuote(char *str, char *delim)
- {
- char *term;
- static char *next=0;
-
- if (!str && ((str=next)==0 || !(*str))) return((char *)0);
-
- /* skip all delimiter characters */
- for (; *str; ++str) if (!strchr(delim,*str)) break;
-
- /* are we done? */
- if (!*str) return(next=(char *)0);
-
- /* check for start of quoted string */
- if (*str == '"') {
- term = strchr(++str,'"'); // terminate at matching quote
- } else {
- /* find next delimiter */
- for (term=str+1; *term; ++term) if (strchr(delim,*term)) break;
- }
-
- if (term && *term) {
- *term = 0; // null terminate this token
- next = term + 1;
- } else {
- next = 0;
- }
-
- return(str);
- }
-
- /*------------------------------------------------------------------------------------------
- ** Mac routines
- */
-
- static Rect progressItemRect;
- static long progressItemValue = -1;
- static Boolean macMode = FALSE;
- static Boolean wne_impl;
- static Rect dragRect;
-
-
- static void ToolBoxInit(void)
- {
- const int WNE_TRAP_NUM = 0x60;
- const int UNIMPL_TRAP_NUM = 0x9f;
-
- macMode = TRUE;
-
- InitGraf(&thePort);
- InitFonts();
- FlushEvents(everyEvent,0);
- InitWindows();
- InitMenus();
- TEInit();
- InitDialogs((ResumeProcPtr)0);
- InitCursor();
-
- wne_impl = (NGetTrapAddress(WNE_TRAP_NUM,ToolTrap) !=
- NGetTrapAddress(UNIMPL_TRAP_NUM,ToolTrap));
-
- dragRect = screenBits.bounds;
- InsetRect(&dragRect, 4, 4);
- }
-
- /* DrawMyItem - user item routine for progress indicator of wait dialog */
- static void pascal DrawMyItem(WindowPtr theWindow, short itemNum)
- {
- int tmp;
- Rect rect;
- static RGBColor colors[] = { { 0xcccc, 0xcccc, 0xffff }, // Baby blue
- { 0x4444, 0x4444, 0x4444 }, // DarkGrey
- };
-
- /* copy the item rect */
- rect = progressItemRect;
-
- /* draw a black frame */
- FrameRect(&rect);
-
- /* draw the indicator background */
- InsetRect(&rect,1,1);
- tmp = rect.left;
- rect.left += (int)((rect.right-rect.left) * progressItemValue / 100);
- RGBBackColor(colors);
- EraseRect(&rect);
-
- /* draw the indicated percentage */
- RGBForeColor(colors + 1);
- rect.right = rect.left;
- rect.left = tmp;
- PaintRect(&rect);
- }
-
- /* ShowProgress - show progress dialog */
- /* (if percent<0 dialog is removed) */
- void ShowProgress(int percent, Boolean forceShow)
- {
- short itemType;
- Handle itemHand, dlogHandle;
- long tmpLong;
- SignedByte savedState;
- static DialogPtr progressDlg = 0;
- const long kProgressDlgID = 200L;
- const long kWaitTime = 10;
- static long nextTime = 0;
- Rect rect;
- GrafPtr oldPort;
-
- if (percent < 0) {
-
- /* dispose the dialog if it exists */
- if (progressDlg) {
-
- DisposDialog(progressDlg);
- progressDlg = 0;
-
- progressItemValue = -1;
- nextTime = 0;
- }
-
- } else {
-
- /* create the dialog if it doesn't exist */
- if (!progressDlg) {
-
- /* must lock resource so it isn't purged in GetNewDialog (!!) */
- /* (if it is purged, the PositionDialog() call would be undone) */
- dlogHandle = GetResource('DLOG', kProgressDlgID);
- savedState = HGetState(dlogHandle);
- HLock(dlogHandle);
-
- /* position dialog and get handle */
- progressDlg = GetNewDialog(kProgressDlgID,NULL,(WindowPtr)-1L);
-
- /* restore the resource memory state */
- HSetState(dlogHandle, savedState);
-
- /* set the drawing proc for the progress indicator item */
- GetDItem(progressDlg,kProgressIndicatorItem,&itemType,&itemHand,&progressItemRect);
- SetDItem(progressDlg,kProgressIndicatorItem,itemType,(Handle)DrawMyItem,&progressItemRect);
- }
-
- if (forceShow || (progressItemValue!=percent && TickCount()>nextTime)) {
-
- /* set the progress value */
- progressItemValue = percent;
-
- /* set the next time to update this indicator */
- nextTime = TickCount() + kWaitTime;
-
- if (forceShow) {
-
- /* draw the whole dialog (to update text too) */
- DrawDialog(progressDlg);
-
- } else {
-
- /* update the progress indicator only */
- GetPort(&oldPort);
- SetPort(progressDlg);
-
- /* invalidate the progress item */
- InvalRect(&progressItemRect);
-
- SetPort(oldPort);
- }
- }
- }
- }
-
- /* Quit - Quit program */
- static void Quit(unsigned char *str)
- {
- unsigned char *pt;
- const int kMsgAlertID = 201;
- const int kLineLen = 50;
-
- if (macMode) {
- ShowProgress(-1,TRUE);
- ParamText(str,"\p","\p","\p");
- NoteAlert(kMsgAlertID,0);
- ExitToShell();
- } else {
- ++str;
- while (*pt) {
- pt = (unsigned char *)strchr((char *)str,'\r');
- if (!pt) pt = (unsigned char *)strchr((char *)str,'\0');
- /* keep lines to 80 chars or less */
- if (pt - str > kLineLen) {
- pt = str + kLineLen;
- while (pt>str && !isspace(*pt)) --pt;
- if (pt == str) pt = str + kLineLen;
- }
- printf("%.*s\n",pt-str,str);
- if (*pt == '\r') printf("\n");
- str = pt + 1;
- }
- exit(1);
- }
- }
-
- /* HandleEvents - process Mac events */
- void HandleEvents()
- {
- EventRecord theEvent;
- short thePart;
- WindowPtr whichWindow;
- DialogPtr theDialog;
- Boolean abort = FALSE;
-
- /* process mac events */
- if (wne_impl) {
- WaitNextEvent(everyEvent, &theEvent, 0L, 0L);
- } else {
- SystemTask();
- GetNextEvent(everyEvent, &theEvent);
- }
-
- /* does the user want to abort? */
- if (theEvent.what==keyDown && theEvent.modifiers&cmdKey && (theEvent.message&0xff)=='.') {
- abort = TRUE;
- } else if (IsDialogEvent(&theEvent)) {
- if (DialogSelect(&theEvent, &theDialog, &thePart)) {
- if (thePart == kStopButtonItem) abort = TRUE;
- }
- } else if (theEvent.what == mouseDown) {
- /* handle window drags */
- thePart = FindWindow(theEvent.where, &whichWindow);
-
- if (thePart == inDrag) {
- SelectWindow(whichWindow);
- DragWindow(whichWindow, theEvent.where, &dragRect);
- }
- }
- if (abort) {
- /* must close net to avoid problems if */
- /* quitting in the middle of a DNS lookup */
- CloseResolver();
-
- Quit("\pWebStat processing halted!\rOutput file not written.\0");
- }
- }
-
- /*------------------------------------------------------------------------------------------
- ** Other routines
- */
-
- /* MemoryError - print memory error message and terminate program */
- static void MemoryError()
- {
- Quit("\pNot enough memory!\rPlease increase the memory size for WebStat using the Get Info option in the File menu.\0");
- }
-
- /* ReverseAddress - reverse an IP address string */
- /* - kills source string */
- /* - returns pointer to last field in addr */
- static char *ReverseAddress(char *src, char *dst)
- {
- char *pt;
- char *last_field = 0;
-
- dst[0] = 0;
-
- while ((pt=strrchr(src,'.')) != 0) {
- if (!last_field) last_field = pt + 1;
- strcat(dst,pt+1);
- strcat(dst,".");
- *pt = 0;
- }
- strcat(dst,src);
-
- return(last_field);
- }
-
- /* GetIPAddress - get numerical address from string */
- static long GetIPAddress(char *hostname)
- {
- int i;
- long addr = 0;
-
- for (i=3;;) {
- addr |= (long)atoi(hostname) << 8*i;
- if (--i < 0) break;
- hostname = strchr(hostname,'.') + 1;
- if (!hostname) return(0L);
- }
- return(addr);
- }
-
- /* ConvTime - get struct tm from time and date strings */
- /* Time and date are in the form "09:57:56" and "03/28/94" */
- /* otherwise a zero is returned. */
- static time_t ConvTime(char *time, char *date, struct tm *tms)
- {
- /* do a quick check on the time and date formats so we can be */
- /* resonably certain that we are looking at the correct strings */
- if (time[2]!=':' || date[2]!='/') return((time_t)0);
-
- tms->tm_sec = atoi(time+6);
- tms->tm_min = atoi(time+3);
- tms->tm_hour = atoi(time);
- tms->tm_mday = atoi(date+3);
- tms->tm_mon = atoi(date) - 1;
- tms->tm_year = atoi(date+6);
- tms->tm_isdst = 0;
-
- return(mktime(tms));
- }
-
- /* ConvDate - convert date of form "03/28/94" to "Mar 28 1994" */
- static char *ConvDate(const char *date)
- {
- static char buff[100];
- static char * months = "JanFebMarAprMayJunJulAugSepOctNovDec";
-
- sprintf(buff,"%3.3s %2d %4d",
- months+3*(atoi(date)-1),
- atoi(date + 3),
- atoi(date + 6) + 1900);
- return(buff);
- }
-
- /* GetDateStr - get date string from ctime() output */
- static void GetDateStr(char *out, char *ctimeStr)
- {
- memcpy(out, ctimeStr+4, 7); // copy month and day
- memcpy(out+7, ctimeStr+20, 4); // copy year
- out[11] = 0; // null terminate it
- }
-
- /* GetNumDays - get the number of days between two time_t values */
- static long GetNumDays(time_t start, time_t end)
- {
- struct tm *tms;
- int day1, year1;
- int day2, year2;
- long numDays;
-
- if (start >= end) return(1); // exit gracefully on bad input
-
- tms = localtime(&start);
- day1 = tms->tm_yday;
- year1 = tms->tm_year;
- tms = localtime(&end);
- day2 = tms->tm_yday;
- year2 = tms->tm_year;
-
- numDays = day2 - day1 + 1;
-
- while (year1 < year2) {
- if (year1 % 4 != 0) numDays += 365L;
- else if (year1 % 100 != 0) numDays += 366L; // leap year
- else numDays += 365L; // 365 days at turn of century
- ++year1;
- }
- if (numDays < 1) numDays = 1;
-
- return(numDays);
- }
-
- /*-----------------------------------------------------------------------------------------
- ** Comparison routines
- */
-
- /* CompStat - compare two statistics string names (used in qsort()) */
- int CompStat(const void *p1, const void *p2)
- {
- char *str1 = ((Statistic *)p1)->name;
- char *str2 = ((Statistic *)p2)->name;
-
- return(strcmpi(str1,str2));
- }
- /* CompStatNum - compare two statistics string names, evaluating numerical addresses */
- int CompStatNum(const void *p1, const void *p2)
- {
- int n1, n2;
- char *str1 = ((Statistic *)p1)->name;
- char *str2 = ((Statistic *)p2)->name;
-
- if (isdigit(*str1) && isdigit(*str2)) {
-
- for (;;) {
- n1 = atoi(str1);
- n2 = atoi(str2);
- if (n1 == n2) {
- str1 = strchr(str1,'.');
- if (!str1) return(0);
- str2 = strchr(str2,'.');
- if (!str2) return(0);
- ++str1;
- ++str2;
- } else if (n1 < n2) {
- return(-1);
- } else {
- return(1);
- }
- }
-
- } else {
-
- return(strcmpi(str1,str2));
- }
- }
-
- /*--------------------------------------------------------------------------------------
- ** StringLookup class methods
- */
- /* StringLookup - class constructor */
- StringLookup::StringLookup(long incr, Boolean part)
- : num(0),maxNum(0),incrNum(incr),partialCompare(part)
- {
- }
-
- /* ~StringLookup - class destructor */
- StringLookup::~StringLookup()
- {
- long i;
-
- /* reset name list */
- if (maxNum) {
- for (i=0; i<num; ++i) delete list[i];
- maxNum = num = 0;
- delete list;
- }
- }
-
- /* AddString - add string to lookup list */
- void StringLookup::Add(char *code, char *name)
- {
- int i;
- char **oldList;
-
- /* expand country list if necessary */
- if (num >= maxNum) {
- oldList = list;
- list = new char *[maxNum + incrNum];
- if (!list) MemoryError();
-
- if (maxNum) {
- memcpy(list, oldList, maxNum * sizeof(char *));
- delete oldList;
- }
- maxNum += incrNum;
- }
-
- /* add country to list */
- i = strlen(code) + strlen(name) + 2;
- list[num] = new char[i];
- if (!list[num]) MemoryError();
- strcpy(list[num],code);
- strcpy(strchr(list[num],'\0')+1,name);
- ++num;
- }
-
- /* Lookup - look up an entry in the list */
- char *StringLookup::Lookup(char *code)
- {
- long i;
-
- /* search for entry in list */
- for (i=0; i<num; ++i) {
- if (partialCompare) {
- if (!strcmpiPart(list[i], code)) return(strchr(list[i],'\0')+1);
- } else {
- if (!strcmpi(list[i], code)) return(strchr(list[i],'\0')+1);
- }
- }
-
- return((char *)0);
- }
-
- /*-----------------------------------------------------------------------------------------
- ** Statistic class methods
- */
- /* Statistic - constructor */
- Statistic::Statistic() : files(0), bytes(0), name(0)
- {
- /* empty method */
- }
-
- /* ~Statistic - destructor */
- Statistic::~Statistic()
- {
- if (name) delete name; // free memory for name
- }
-
- /* IncrStats - increment statistics counters */
- void Statistic::IncrStats(double byte_count)
- {
- files++;
- bytes += byte_count;
- }
-
- /*-----------------------------------------------------------------------------------------
- ** StatList class methods
- */
- /* StatList - constructor */
- StatList::StatList(long iSize) : num(0)
- {
- incrSize = maxNum = iSize;
-
- stat = new Statistic[iSize];
-
- if (!stat) MemoryError();
- }
-
- /* ~StatList - destructor */
- StatList::~StatList()
- {
- /* delete all Statistic objects */
- for (long n=0; n<maxNum; ++n) delete(stat+n);
- }
-
- /* Write - write list to file */
- void StatList::Write(FILE *fp, char *heading)
- {
- int i,len;
- long n;
- double totFile, totByte;
- const int BSIZ = 256;
- char *name, buff[BSIZ];
-
- len = strlen(heading);
-
- if (len > BSIZ) return;
-
- memset(buff,'-',len);
- buff[len] = 0;
-
- if (!totalFiles) totFile = 1; // avoid divide by zero
- else totFile = totalFiles / 100.0;
-
- if (!totalBytes) totByte = 1;
- else totByte = totalBytes / 100.0;
-
- fprintf(fp,"<pre>\n");
- fprintf(fp,"%*s Number of Number of Percent of Percent of\n",len,"");
- fprintf(fp, "%s Files Sent Bytes Sent Files Sent Bytes Sent\n",heading);
- fprintf(fp, "%s ---------- ------------ ---------- ----------\n",buff);
-
- ++len;
-
- for (n=0; n<num; ++n) {
-
- if ((i=strlen(stat[n].name))<=len || len<3) {
- name = stat[n].name;
- } else {
- strcpy(buff,"...");
- strcat(buff,stat[n].name+i-len+3);
- name = buff;
- }
-
- fprintf(fp,"%-*s %10ld %13.0f %6.2f %6.2f\n",
- len,
- name,
- stat[n].files,
- stat[n].bytes,
- stat[n].files / totFile,
- stat[n].bytes / totByte);
- }
- fprintf(fp,"</pre><p>\n");
- }
-
- /* SearchStat - search list for matching string, creating new entry if not found */
- long StatList::SearchStat(char *str)
- {
- long n;
- Statistic *tempStat;
-
- /* search through stat names (most recent first for speed) */
- for (n=num-1; n>=0; --n) {
- if (!strcmpi(str,stat[n].name)) return(n);
- }
- if (num >= maxNum) {
- tempStat = new Statistic[maxNum + incrSize];
- if (!tempStat) MemoryError();
- for (n=0; n<maxNum; ++n) {
- tempStat[n] = stat[n];
- stat[n].name = 0; // make sure memory is not deallocated for name
- }
- delete stat;
- stat = tempStat;
- maxNum += incrSize;
- }
- stat[num].name = new char[strlen(str)+1];
- if (!stat[num].name) MemoryError();
- strcpy(stat[num].name,str);
- return(num++);
- }
-
- /* IncrStats - increment the stats for given string */
- void StatList::IncrStats(double byte_count, char *str)
- {
- long n;
-
- n = SearchStat(str);
-
- stat[n].IncrStats(byte_count); // increment individual sums
- }
-
- /* IncrTotals - increment total counters */
- void StatList::IncrTotals(double byte_count)
- {
- totalFiles++; // increment totals
- totalBytes += byte_count;
- }
-
- /* Substitute - substitute names in list */
- void StatList::Substitute(char *(*func)(const char *))
- {
- char *pt, *pt2;
-
- for (long n=0; n<num; ++n) {
- pt = func(stat[n].name); // get new string
- if (pt) {
- pt2 = new char[strlen(pt) + 1];
- if (!pt2) MemoryError();
- strcpy(pt2,pt); // copy the string
- delete stat[n].name; // get rid of old string
- stat[n].name = pt2;
- }
- }
- }
-
- /* Sort - sort the list alphabetically */
- void StatList::Sort(CompFunc func)
- {
- if (!func) func = CompStat;
-
- qsort(stat, num, sizeof(Statistic), func);
- }
-
- /* Summarize - print summary of total day statistics */
- void StatList::Summarize(FILE *fp, time_t first, time_t last)
- {
- char firstStr[30];
- char lastStr[30];
- long num;
-
- num = GetNumDays(first, last);
-
- GetDateStr(firstStr, ctime(&first));
- GetDateStr(lastStr, ctime(&last));
-
- fprintf(fp,"<h2>Summary for Period: %s to %s</h2>\n", firstStr, lastStr);
- fprintf(fp,"<pre>\n");
- fprintf(fp,"Files Transmitted During Summary Period %14d\n",totalFiles);
- fprintf(fp,"Bytes Transmitted During Summary Period %14.0f\n",totalBytes);
- fprintf(fp,"Average Files Transmitted Daily %14d\n",totalFiles/num);
- fprintf(fp,"Average Bytes Transmitted Daily %14.0f\n",totalBytes/num);
- fprintf(fp,"</pre><p>\n");
- }
-
- /*-----------------------------------------------------------------------------------------
- ** main program
- */
- void main()
- {
- long i, line, fileSize;
- long numExcl = 0, maxExcl = 0;
- long numCtry = 0;
- char *logFile = def_log_file;
- char *outFile = def_out_file;
- char *fmtFile = def_fmt_file;
- Boolean messages = FALSE;
- Boolean long_addr = TRUE;
- Boolean dnsLookup = FALSE;
- Boolean isReverse;
- time_t tt, firstTime, lastTime;
- struct tm tms;
- char *pt,*pt2, *pt3, *country, *last_field;
- char *domain,*file,*time_str,*date_str,*stat_str;
- char **exclude, **oldExcl;
- const int BSIZ = 512;
- Str255 curVol;
- short vRefNum;
- char rev_domain[BSIZ],buff[BSIZ],dns_name[BSIZ],buf2[BSIZ];
- StringLookup *countryList, *addressList;
- double bytes;
- StatList *byDate, *byHour, *byWeekday, *byDomain, *bySubdomain, *byFile;
- FILE *fp, *out, *fmt;
- static char *syntaxFmt = "Syntax error in %s line %ld: %s '%s'\n";
- static char *delim = " \t\n";
- static char *weekdays[] = { "Sunday","Monday","Tuesday","Wednesday",
- "Thursday","Friday","Saturday" };
-
- firstTime = 0;
-
- /* initialize country list object */
- countryList = new StringLookup(kCountryIncr,TRUE);
- if (!countryList) MemoryError();
-
- /* read config file */
- if ((fp = fopen(config_file,"r")) == 0) {
- printf("Config file %s not found!\nUsing defaults.\n",config_file);
- } else {
- for (line=1; fgets(buff,BSIZ,fp); ++line) {
-
- pt = strtokQuote(buff,delim);
- if (!pt || *pt=='#') continue;
-
- pt2 = strtokQuote(NULL,delim);
- if (!pt2) {
- printf(syntaxFmt,config_file,line,"No parameters for",pt);
- continue;
- }
-
- if (!strcmpi(pt,"LOG")) {
- logFile = new char[strlen(pt2) + 1];
- if (!logFile) MemoryError();
- strcpy(logFile, pt2);
-
- } else if (!strcmpi(pt,"OUTPUT")) {
- outFile = new char[strlen(pt2) + 1];
- if (!outFile) MemoryError();
- strcpy(outFile, pt2);
-
- } else if (!strcmpi(pt,"FORMAT")) {
- fmtFile = new char[strlen(pt2) + 1];
- if (!fmtFile) MemoryError();
- strcpy(fmtFile, pt2);
-
- } else if (!strcmpi(pt,"EXCLUDE")) {
- if (numExcl >= maxExcl) {
- oldExcl = exclude;
- exclude = new char *[maxExcl + kExcludeIncr];
- if (!exclude) {
- printf("Too many exclusions\n");
- MemoryError();
- }
- if (maxExcl) {
- memcpy(exclude, oldExcl, maxExcl * sizeof(char *));
- delete oldExcl;
- }
- maxExcl += kExcludeIncr;
- }
- exclude[numExcl] = new char[strlen(pt2) + 1];
- if (!exclude[numExcl]) MemoryError();
- strcpy(exclude[numExcl], pt2);
- ++numExcl;
-
- } else if (!strcmpi(pt,"MESSAGES")) {
- if (!strcmpi(pt2,"On")) messages = TRUE;
-
- } else if (!strcmpi(pt,"ADDRESSES")) {
- if (!strcmpi(pt2,"Short")) long_addr = FALSE;
-
- } else if (!strcmpi(pt,"DOMAIN")) {
- pt3 = strchr(pt2,'*');
- if (pt3) *pt3 = 0; // get rid of '*' if it exists
- pt3 = strtokQuote(NULL,delim);
- if (!pt3) {
- printf(syntaxFmt,config_file,line,"Too few parameters for",pt);
- continue;
- }
- countryList->Add(pt2, pt3);
- ++numCtry;
-
- } else if (!strcmpi(pt,"DNSLOOKUP")) {
- if (!strcmpi(pt2,"On")) dnsLookup = TRUE;
-
- } else {
- printf(syntaxFmt,config_file,line,"Unknown keyword",pt);
- }
- }
- fclose(fp);
- }
-
- if (messages) {
- printf("\n*****************************\n");
- printf("** --- %s --- **\n",program_name);
- printf("** A utility for MacHTTP **\n");
- printf("** by Phil Harvey **\n");
- printf("*****************************\n\n");
- if (numCtry) printf("%ld domain name%s registered.\n",numCtry,numCtry==1?"":"s");
- if (numExcl) printf("%ld exclusion%s registered.\n",numExcl,numExcl==1?"":"s");
- if (numCtry || numExcl) printf("\n");
- }
-
- /* open log file */
- if ((fp = fopen(logFile,"r")) == 0) {
- printf("Can't open log file %s !\n\n",logFile);
- printf("The log file name can be specified in WebStat.config.\n");
- printf("If no path is specified, then the log file\n");
- printf("must be in the same folder as the WebStat program.\n");
- exit(1);
- }
-
- /* open format file */
- if ((fmt = fopen(fmtFile,"r")) == 0) {
- printf("Can't open the HTML format file %s !\n\n",fmtFile);
- printf("If no path is specified, then the format file\n");
- printf("must be in the same folder as the WebStat program.\n");
- exit(1);
- }
-
- if (!messages) {
- ToolBoxInit();
- ParamText("\pProcessing log file","\p","\p","\p");
- ShowProgress(0,TRUE);
- }
-
- /* initialize lists */
- byDate = new StatList(kDateIncr);
- byHour = new StatList(kHourIncr);
- byWeekday = new StatList(kWDayIncr);
- byDomain = new StatList(kDomainIncr);
- bySubdomain = new StatList(kSubDomainIncr);
- byFile = new StatList(kFileIncr);
-
- /* initialize weekday and hour names */
- for (i=0; i<7; ++i) byWeekday->SearchStat(weekdays[i]);
- for (i=0; i<24; ++i) {
- sprintf(buf2," %.2ld",i);
- byHour->SearchStat(buf2);
- }
-
- /* init MacTCP if doing DNS lookups */
- if (dnsLookup) {
-
- /* get current volume (DNS routines change this!) */
- GetVol(curVol,&vRefNum);
-
- /* initialize DNS lookup cache table */
- addressList = new StringLookup(kDNSListIncr,FALSE);
- if (!addressList) MemoryError();
- if (messages) printf("Initializing MacTCP...\n");
- if (InitNetwork() != noErr) {
- Quit("\pNet init error!\rYou may want to set DNSLOOKUP Off in your WebStat.config file.\0");
- }
- }
-
- /* read the log file */
- if (messages) {
- printf("Reading file %s...\n",logFile);
- } else {
- /* get size of file */
- fseek(fp,0L,SEEK_END);
- fileSize = ftell(fp);
- if (!fileSize) ++fileSize; // prevent /0 errors
- fseek(fp,0L,SEEK_SET);
- }
-
- while (fgets(buff,BSIZ,fp)) {
-
- if (!messages) {
-
- /* handle events */
- HandleEvents();
-
- /* update the progress indicator */
- ShowProgress(ftell(fp)*100L/fileSize, FALSE);
- }
-
- date_str = strtok(buff,delim);
- time_str = strtok(NULL,delim);
- stat_str = strtok(NULL,delim);
- domain = strtok(NULL,delim);
- file = strtok(NULL,delim);
- bytes = atof(strtok(NULL,delim));
-
- /* ignore lines that don't have enough entries */
- if (!file) continue;
-
- /* convert the time and date strings */
- tt = ConvTime(time_str, date_str, &tms);
-
- /* ignore line if the date didn't convert properly */
- if (!tt) continue;
-
- /* save first and last times */
- if (!firstTime) firstTime = tt;
- lastTime = tt;
-
- /* clean up address string and determine if it is reversed */
- isReverse = TRUE;
- if (isdigit(domain[0])) {
- pt = strstr(domain,".in-addr"); // get rid of ".in-addr.arpa."
- if (pt) *pt = 0;
- else isReverse = FALSE; // NO_DNS option must be on (name not rev)
- } else {
- domain[strlen(domain)-1] = 0; // get rid of trailing '.'
- }
-
- /* reverse the subdomain if necessary */
- if (isReverse) {
- last_field = ReverseAddress(domain,rev_domain);
- } else {
- strcpy(rev_domain,domain);
- }
-
- /* resolve all numerical addresses if DNSLOOKUP is On */
- if (dnsLookup && isdigit(rev_domain[0])) {
-
- /* does this entry exist in address cache? */
- pt = addressList->Lookup(rev_domain);
-
- /* if not found, consult DNS for translation */
- if (!pt) {
-
- if (messages) printf("DNS lookup %s -> ",rev_domain);
-
- /* get resolved address in buf2 */
- if (IPAddrToName(GetIPAddress(rev_domain),dns_name) == noErr) {
-
- dns_name[strlen(dns_name)-1] = 0; // get rid of trailing '.'
-
- if (messages) printf("%s\n",dns_name);
-
- /* must reverse the name returned by DNS */
- last_field = ReverseAddress(dns_name, buf2);
-
- /* add to name cache */
- addressList->Add(rev_domain, buf2);
-
- /* copy new name into domain string */
- strcpy(rev_domain, buf2);
-
- } else {
-
- /* use unresolved name if host unknown */
- addressList->Add(rev_domain, rev_domain);
-
- if (messages) printf("<unknown>\n");
- }
-
- } else {
-
- /* use the converted name from the cache */
- strcpy(rev_domain, pt);
- }
- }
-
- /* check for exclusions */
- for (i=0; i<numExcl; ++i) {
- if (!strcmpiWild(exclude[i],rev_domain)) break;
- }
- if (i != numExcl) continue;
-
- /* parse filespec */
- for (pt=file; *pt; ++pt) {
- if (*pt==':') {
- if (pt[1]) *pt = '/'; // convert ':' to '/'
- else *pt = 0;
- } else if (*pt=='?' || *pt=='$') {
- *pt = 0; // truncate file names at '?' or '$'
- break;
- }
- }
-
- /* increment totals */
- StatList::IncrTotals(bytes);
-
- /* weekly totals */
- byWeekday->IncrStats(bytes, weekdays[tms.tm_wday]);
-
- /* hourly totals */
- sprintf(buf2," %.2d",tms.tm_hour);
- byHour->IncrStats(bytes, buf2);
-
- /* daily totals */
- byDate->IncrStats(bytes, date_str);
-
- /* totals by domain */
- country = countryList->Lookup(rev_domain);
- if (!country) {
- if (isdigit(rev_domain[0])) country = "[unresolved]";
- else country = last_field;
- }
- byDomain->IncrStats(bytes, country);
-
- /* shorten address if requested for subdomain list */
- if (!long_addr) {
- pt = strrchr(rev_domain,'.');
- if (pt) *pt = 0;
- }
-
- /* totals by subdomain */
- bySubdomain->IncrStats(bytes, rev_domain);
-
- /* totals by file */
- if (memcmp(stat_str,"OK",2)) pt = "[nonexistent files]";
- else pt = file;
- byFile->IncrStats(bytes, pt);
-
- }
-
- /* close log file */
- fclose(fp);
-
- /* convert date formats */
- byDate->Substitute(ConvDate);
-
- /* sort the stuff */
- byDomain->Sort();
- bySubdomain->Sort(CompStatNum);
- byFile->Sort();
-
- /* print results */
- if (messages) {
- printf("Writing file %s...\n",outFile);
- } else {
- ParamText("\pWriting output file","\p","\p","\p");
- ShowProgress(100,TRUE);
- }
-
- /* reset current volume if necessary */
- if (dnsLookup) SetVol(curVol,vRefNum);
-
- /* open output file */
- if ((out = fopen(outFile,"w")) == 0) {
- Quit("\pCan't open output file!\rAre your sure the output folder exists, and is not locked?\0");
- }
-
- while (fgets(buff, BSIZ, fmt)) {
-
- /* interpret special codes in format file */
- if (buff[0] == '[') {
- if (!strcmpiPart("[Summary]",buff)) {
- time(&tt);
- fprintf(out,"Generated by: %s<br>\n",program_name);
- fprintf(out,"Last updated: %s<p>\n",ctime(&tt));
- StatList::Summarize(out, firstTime, lastTime);
- continue;
- } else if (!strcmpiPart("[Day]",buff)) {
- byDate->Write(out," Date ");
- continue;
- } else if (!strcmpiPart("[Hour]",buff)) {
- byHour->Write(out,"Time");
- continue;
- } else if (!strcmpiPart("[Weekday]",buff)) {
- byWeekday->Write(out," Day ");
- continue;
- } else if (!strcmpiPart("[Domain]",buff)) {
- byDomain->Write(out," Domain Name ");
- continue;
- } else if (!strcmpiPart("[Subdomain]",buff)) {
- bySubdomain->Write(out," Reversed Subdomain ");
- continue;
- } else if (!strcmpiPart("[Archive]",buff)) {
- byFile->Write(out," Archive Section ");
- continue;
- }
- }
-
- /* no special code found, copy line to the output */
- fputs(buff,out);
- }
- fclose(out);
- fclose(fmt);
-
- /* free up memory */
- delete byDate;
- delete byHour;
- delete byWeekday;
- delete byDomain;
- delete bySubdomain;
- delete byFile;
-
- /* delete exclusions */
- if (numExcl) {
- for (i=0; i<numExcl; ++i) delete exclude[i];
- delete exclude;
- }
-
- /* free country list */
- delete countryList;
-
- /* free DNS cache if allocated */
- if (dnsLookup) delete addressList;
-
- if (messages) {
- printf("Done.\n");
- } else {
- ShowProgress(-1,TRUE);
- }
- }